/**   
 * @Title: ResourceService.java 
 * @Package com.betterjr.modules.workflow.snaker.core 
 * @Description: 流程实例操作类
 * @author licz
 * @date 2017年10月30日 下午3:03:48  
 */
package com.betterjr.modules.risk.loanmanage.service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import com.betterjr.common.selectkey.SerialGenerator;
import com.betterjr.common.service.BaseService;
import com.betterjr.common.utils.BTAssert;
import com.betterjr.common.utils.BetterDateUtils;
import com.betterjr.common.utils.UserUtils;
import com.betterjr.mapper.pagehelper.Page;
import com.betterjr.modules.accountSupervision.service.ScfWarnService;
import com.betterjr.modules.risk.loan.service.LoanProjectRelationService;
import com.betterjr.modules.risk.loanmanage.dao.PaymentPlanMapper;
import com.betterjr.modules.risk.loanmanage.dubbo.LoanManageDubboService;
import com.betterjr.modules.risk.loanmanage.entity.PaymentData;
import com.betterjr.modules.risk.loanmanage.entity.PaymentPlan;
import com.betterjr.modules.risk.loanmanage.remote.RomoteUtil;
import com.betterjr.modules.risk.loanmanage.remote.XmlUtil;
import com.betterjr.modules.risk.loanmanage.util.BetterBeanUtils;

@Service
public class PaymentPlanService extends BaseService<PaymentPlanMapper, PaymentPlan> {

    @Inject
    PaymentDataService paymentDataService;

    @Inject
    LoanProjectRelationService loanProjectRelationService;

    @Inject
    LoanManageDubboService loanManageDubboService;

    @Inject
    LoanDataService loanDataService;

    @Inject
    ScfWarnService scfWarnService;

    // -1没完成(默认)，0完成，1部分完成，2逾期 ，3取消
    public Page<PaymentPlan> listPaymentPlan(final PaymentPlan paymentPlan, final int pageNum, final int pageSize) {
        return this.selectByPage(paymentPlan, pageNum, pageSize, true);
    }

    public void cancelPaymentPlanByContractId(final Long contractId) {
        final PaymentPlan paymentPlan = new PaymentPlan();
        paymentPlan.setContractId(contractId);
        final List<PaymentPlan> list = select(paymentPlan);
        for (final PaymentPlan plan : list) {
            // 已激活推送 且 未完成的 需要取消了
            if ("0".equals(plan.getActivationFlag()) && !"0".equals(plan.getStatus())) {
                cancelPaymentPlanById(plan.getId());
            }
        }
    }

    public void cancelPaymentPlanByLoanDataId(final Long loanDataId) {
        final PaymentPlan paymentPlan = new PaymentPlan();
        paymentPlan.setLoanDataId(loanDataId);
        final List<PaymentPlan> list = select(paymentPlan);
        for (final PaymentPlan plan : list) {
            // 已激活推送 且 未完成的 需要取消了
            if ("0".equals(plan.getActivationFlag()) && !"0".equals(plan.getStatus())) {
                cancelPaymentPlanById(plan.getId());
            }
        }
    }

    public void cancelPaymentPlanById(final Long id) {
        // 1.调用运资金 计划取消
        final PaymentPlan tmpPaymentPlan = this.selectByPrimaryKey(id);
        BTAssert.notNull(tmpPaymentPlan, "查不到计划数据!!");
        // 支持批量
        final List delIdList = new ArrayList<>();
        final Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        delIdList.add(map);

        final Map<String, Object> result = RomoteUtil.callService(tmpPaymentPlan.getPaymentCustomerId(),
                "PlanRepaymentSettle", delIdList);
        if (!"0".equals(result.get("code"))) {
            // 处理失败了
            BTAssert.isTrue(false, "云资金取消失败：" + result.get("message"));
        }
        // 2.修改计划状态
        final PaymentPlan paymentPlan = new PaymentPlan();
        paymentPlan.setId(id);
        paymentPlan.setStatus("3");
        updateByPrimaryKeySelective(paymentPlan);
    }

    public PaymentPlan savePaymentPlan(final Map<String, Object> param) {

        final PaymentPlan paymentPlan = new PaymentPlan();
        BetterBeanUtils.copyProperties2Bean(paymentPlan, param);
        BTAssert.notNull(paymentPlan, "参数不允许为空！");

        return savePaymentPlan(paymentPlan);
    }

    /** 
     * @Title: savePaymentPlan 
     * @Description: 创建、更新 扣款计划，计划推送至运资金管理平台
     * @param paymentPlan
     * @return 
     * @throws 
     * @author licz
     * @date 2018年6月27日 下午4:27:46 
     */
    public PaymentPlan savePaymentPlan(final PaymentPlan paymentPlan) {
        paymentPlan.setUpdateCreatorId(UserUtils.getUser().getId());
        paymentPlan.setUpdateCreator(UserUtils.getUser().getName());
        paymentPlan.setUpdateDate(Timestamp.valueOf(BetterDateUtils.getDateTime()));
        paymentPlan.setCreatorId(UserUtils.getUser().getId());
        paymentPlan.setCreator(UserUtils.getUser().getName());
        paymentPlan.setCreateDate(Timestamp.valueOf(BetterDateUtils.getDateTime()));
        if (!ObjectUtils.isEmpty(paymentPlan.getId())) {
            this.updateByPrimaryKeySelective(paymentPlan);
        } else {
            final Long baseId = SerialGenerator.getLongValue(PaymentPlan.selectKey);
            paymentPlan.setId(baseId);
            this.insertSelective(paymentPlan);
        }
        // 0代表激活，不推送是云资金管理
        if ("0".equals(paymentPlan.getActivationFlag())) {
            final BeanMap beanMap = BeanMap.create(paymentPlan);
            RomoteUtil.callService(paymentPlan.getPaymentCustomerId(), "PlanRepaymentCpf", beanMap);
        }
        return paymentPlan;
    }

    /** 
     * @Title: queryRemotePlanRunData 
     * @Description:查询企E金服未完成的计划在 云资金系统的执行的结果数据，回写 企E
     * @throws 
     * @author licz
     * @date 2018年7月5日 下午1:53:28 
     */
    public void writeBackRemotePlanData() {
        // 1.查询未完成的计划，且已经推送过去的计划
        final Map<String, Object> propertyMap = new HashMap<>();
        propertyMap.put("status", new String[] { "-1", "1", "2" });// -1没完成(默认)，0完成，1部分完成，2逾期 ，3取消
        propertyMap.put("activationFlag", "0");// 激活标志（是否推送运资金）0推送
        final List<PaymentPlan> resultList = this.selectByClassProperty(PaymentPlan.class, propertyMap);
        // 2.激活的，但是推送失败的，继续推送一次。 //TODO 目前没有这个逻辑，不用实现
        // 3. 根据客户id分组批量查询，客户id一样的，服务器地址系统标志一样，节省性能
        final Map<Long, List<Map<String, Object>>> groupPlanByCust = new HashMap();
        List<Map<String, Object>> tmpList = null;
        Map<String, Object> tmpParamIdMap = null;
        for (final PaymentPlan paymentPlan : resultList) {
            tmpParamIdMap = new HashMap<>();
            tmpParamIdMap.put("id", paymentPlan.getId());
            if (groupPlanByCust.containsKey(paymentPlan.getPaymentCustomerId())) {
                groupPlanByCust.get(paymentPlan.getPaymentCustomerId()).add(tmpParamIdMap);
            } else {
                tmpList = new ArrayList<>();
                tmpList.add(tmpParamIdMap);
                groupPlanByCust.put(paymentPlan.getPaymentCustomerId(), tmpList);
            }
        }

        for (final Long custId : groupPlanByCust.keySet()) {
            logger.info("查询扣款数据开始批量执行 start：custId--" + custId + "$ids--" + groupPlanByCust.get(custId));
            try {
                processResutl(RomoteUtil.callService(custId, "QueryPlanRepayment", groupPlanByCust.get(custId)));
            }
            catch (final Exception e) {
                logger.error("定时查询扣款数据QueryPlanRepayment失败：" + e.getMessage(), e);
            }
            logger.info("查询扣款数据开始批量执行 end：custId--" + custId + "$ids--" + groupPlanByCust.get(custId));
        }

    }

    private void processResutl(final Map<String, Object> resutl) {
        logger.info("processResutl定时查询扣款数据-返回数据resutl:" + resutl);
        if (resutl != null && resutl.get("data") != null) {
            final List<Map<String, Object>> data = (List<Map<String, Object>>) resutl.get("data");
            // 状态 云资金对应 ----100 扣款成功 ; 70 等待结果; 90 扣款失败; 95 交易异常; 99 扣款部分成功; 60 等待发送;
            for (final Map<String, Object> listEl : data) {
                for (final String idKey : listEl.keySet()) {
                    if (listEl.get(idKey) instanceof List) {
                        final List<Map<String, String>> entityList = (List<Map<String, String>>) listEl.get(idKey);
                        this.writeBackData(idKey, entityList);// 处理扣款表的记录
                        // 条用异常处理服务
                        scfWarnService.writeBackPlanData(idKey, entityList);

                    }
                }

            }

        }
    }

    private void writeBackData(final String planId, final List<Map<String, String>> planData) {
        final PaymentPlan paymentPlan = this.selectByPrimaryKey(Long.parseLong(planId));

        // BTAssert.notNull(paymentPlan, "查询不到计划信息！");

        if (paymentPlan == null) {
            logger.error("writeBackPlanData定时查询扣款数据，云资金返回的planId[" + planId + "]不存在：查询不到计划信息！");
            return;
        }

        final List<PaymentData> paymentDataList = paymentDataService.selectByProperty("paymentPlanId",
                Long.parseLong(planId));
        final List<Map<String, String>> validDatas = filterValidDatas(planData, paymentDataList);
        logger.info("writeBackPlanData定时查询扣款数据-有效数据列表validDatas:" + validDatas);
        if (CollectionUtils.isEmpty(validDatas)) {
            return;
        }
        String lastStatus = "";
        for (final Map<String, String> paymentMapData : validDatas) {
            final PaymentData paymentData = new PaymentData();
            BetterBeanUtils.copyProperties2Bean(paymentData, paymentMapData);
            paymentData.setId(null);
            paymentData.setPaymentPlanId(Long.parseLong(planId));
            final String realAmount = paymentMapData.get("amount");// 实扣
            final String realPaymentDate = paymentMapData.get("paymentDate");// 实扣
            if (StringUtils.isBlank(realAmount) || StringUtils.isBlank(realPaymentDate)) {
                logger.error("writeBackPlanData定时查询扣款数据-返回数据处理失败 日期或金额为空amount:{};realPaymentDate:{};", realAmount,
                        realPaymentDate);
                return;
            }

            // 实际 扣取情况
            paymentData.setRealAmount(new BigDecimal(realAmount));

            // "yyyy-MM-dd HH:mm:ss" 平台工具不能解析带有 毫秒的时间字符串
            final SimpleDateFormat format = new SimpleDateFormat(BetterDateUtils.DATETIME_DEFFMT);
            try {
                paymentData.setRealPaymentDate(new Timestamp(format.parse(realPaymentDate).getTime()));
            }
            catch (final Exception e) {
                logger.error("writeBackPlanData定时查询扣款数据-写入数据日期解析失败realPaymentDate：" + realPaymentDate, e);
                return;
            }

            // 计划 扣取情况
            paymentData.setAmount(paymentPlan.getAmount());
            paymentData.setPaymentDate(paymentPlan.getPaymentDate());
            paymentData.setPaymentType(paymentPlan.getPaymentType());
            paymentData.setLoanDataId(paymentPlan.getLoanDataId());
            logger.info("writeBackPlanData定时查询扣款数据-写入扣款数据savePaymentData:" + paymentData.toString());
            // 扣款数据录入---云资金按时间排序，所以最后一条状态是新的，所以同步这个状态，状态只会存在，【部分完成， 完成】 两种， 逾期的需要再异常处理服务去处理
            paymentDataService.savePaymentData(paymentData);
            lastStatus = paymentMapData.get("status");
        }

        // 最后一次状态最新状态刷新到计划表
        paymentPlan.setStatus(lastStatus);// 计划状态 定时跑的，user信息system
        paymentPlan.setUpdateCreator("system");
        paymentPlan.setUpdateCreatorId(1L);
        paymentPlan.setUpdateDate(Timestamp.valueOf(BetterDateUtils.getDateTime()));
        logger.info("writeBackPlanData定时查询扣款数据-同步更新plan状态:" + paymentPlan.toString());
        this.updateByPrimaryKey(paymentPlan);

        // 回写 贷款项目状态 ，数据中心交易数据状态 状态完成 调用 ：解释：LoanDataId 不为空，代表是还息和还本的数据， 也可用类型过来作为条件
        if ("0".equals(lastStatus) && paymentPlan.getLoanDataId() != null && paymentPlan.getLoanDataId() != 0L) {
            logger.info("writeBackPlanData定时查询扣款数据---同步回写数据中心目状态:" + paymentPlan.getLoanDataId());
            loanManageDubboService.callDataCenterChangeLoanStatus(paymentPlan.getLoanDataId(), "2");// 1表示未结清，2表示已结清
            final Long contractId = loanDataService.selectByPrimaryKey(paymentPlan.getLoanDataId()).getContractId();
            logger.info("writeBackPlanData定时查询扣款数据---贷款项目状态contractId:" + contractId);
            loanProjectRelationService.saveLoanFinish(contractId);
        }
    }

    private List<Map<String, String>> filterValidDatas(final List<Map<String, String>> planData,
            final List<PaymentData> sourPaymentDataList) {
        final List<Map<String, String>> validDatas = new ArrayList<>();
        for (final Map<String, String> map : planData) {
            // 0才是有效数据 成功
            if (!"0".equals(map.get("retCode"))) {
                continue;
            }

            final String realAmount = map.get("amount");// 实扣
            final String realPaymentDate = map.get("paymentDate");// 实扣
            for (final PaymentData paymentData : sourPaymentDataList) {
                if (BetterDateUtils.formatDate(paymentData.getRealPaymentDate(), BetterDateUtils.DATETIME_DEFFMT)
                        .equals(realPaymentDate) && paymentData.getAmount().toString().equals(realAmount)) {
                    break;
                }
            }

            // 状态 云资金对应 ----100 扣款成功 ; 70 等待结果; 90 扣款失败; 95 交易异常; 99 扣款部分成功; 60 等待发送;
            if ("100".equals(map.get("status")) || "99".equals(map.get("status"))) {
                // 设置成本地对应状态码
                map.put("status", "100".equals(map.get("status")) ? "0" : "1");
                validDatas.add(map);
            }

        }

        return validDatas;
    }

    /** 
     * @Title: saveWTPaymentPlanData    目前废弃，无用
     * @Description:   回写扣款数据 
     * @throws 
     * @author licz
     * @date 2018年7月5日 上午11:42:07 
     */
    public void writeBackPlanData(final String responseData) {

        final PaymentData paymentData = new PaymentData();

        final Long paymentPlanId = Long.parseLong(XmlUtil.getElNameText(responseData, "id"));
        final PaymentPlan paymentPlan = this.selectByPrimaryKey(paymentPlanId);

        BTAssert.notNull(paymentPlan, "PaymentPlan不允许为空！");
        final String realAmount = XmlUtil.getElNameText(responseData, "amount");// 实扣
        final String realPaymentDate = XmlUtil.getElNameText(responseData, "paymentdate");// 实扣

        paymentData.setPaymentPlanId(paymentPlanId);
        // 实际 扣取情况
        paymentData.setRealAmount(new BigDecimal(realAmount));
        paymentData.setRealPaymentDate(Timestamp.valueOf(realPaymentDate));
        // 计划 扣取情况
        paymentData.setAmount(paymentData.getAmount());
        paymentData.setPaymentDate(paymentData.getPaymentDate());
        paymentData.setPaymentType(paymentData.getPaymentType());
        paymentData.setLoanDataId(paymentData.getLoanDataId());
        // 扣款数据录入
        paymentDataService.savePaymentData(paymentData);

        // 更新计划状态
        final String planStatus = XmlUtil.getElNameText(responseData, "status");// 计划状态
        paymentPlan.setStatus(planStatus);// 计划状态 定时跑的，user信息system
        paymentPlan.setUpdateCreator("system");
        paymentPlan.setUpdateCreatorId(1L);
        paymentPlan.setCreateDate(Timestamp.valueOf(BetterDateUtils.getDateTime()));
        this.updateByPrimaryKey(paymentPlan);
    }

}
